#include "opt.h"

void optCentroid(Vertex* v) {
    Vector3d newPos = Vector3d(0, 0, 0);
    for (unsigned int i = 0; i < v->edges.size(); i++) {
        newPos += v->edges[i]->getOpposite(v)->pos;
    }
    newPos /= v->edges.size();
    v->pos = newPos;
}

void optSurfaceArea(Vertex* v) {
    double approxArea = v->approxArea() * 0.99;
    Vector3d origPos = v->pos;

    double minDist = (v->pos - v->edges[0]->getOpposite(v)->pos).magnitude();
    for (int i = 0; i < v->N; i++) {
        double dist = (v->pos - v->edges[i]->getOpposite(v)->pos).magnitude();
        if (dist < minDist) minDist = dist;
    }

    Vector3d offset = Vector3d::randomCube(-minDist, minDist);
    double factor = 1.0/16.0;
    for (int i = 0; i < 20; i++) {
        v->pos += offset * factor;
        double newApproxArea = v->approxArea();
        if (newApproxArea < approxArea) return;
        v->pos = origPos;
        factor *= -1.0/2.0;
    }

    v->pos = origPos;
}

void optMeanCurvature(Vertex* v) {
    v->calculateCurvatures();
    double meanCurvatureSq = v->approxLocalMeanCurvatureSq() * 0.99;
    Vector3d origPos = v->pos;

    double minDist = (v->pos - v->edges[0]->getOpposite(v)->pos).magnitude();
    for (int i = 0; i < v->N; i++) {
        double dist = (v->pos - v->edges[i]->getOpposite(v)->pos).magnitude();
        if (dist < minDist) minDist = dist;
    }

    Vector3d offset;
    //offset = Vector3d::randomCube(-minDist, minDist);
    offset = v->normal * minDist;
    double factor = 1.0/16.0;
    for (int i = 0; i < 20; i++) {
        v->pos += offset * factor;
        double newMeanCurvatureSq = v->approxLocalMeanCurvatureSq();
        if (newMeanCurvatureSq < meanCurvatureSq) break;
        v->pos = origPos;
        factor *= -1.0/2.0;
    }

    v->calculateCurvatures();
}
